/*
 * Copyright 2014-2026 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wzq.framework.util;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.servlet.support.RequestContext;

import freemarker.ext.beans.HashAdapter;
import freemarker.ext.servlet.HttpRequestHashModel;

/**
 * web, request, response相关工具类
 * @author <a href="mailto:yanghao@0easy.com">杨浩</a>
 */
public class UtilWeb {
	protected static final Logger logger = LogManager.getLogger(UtilWeb.class);
	
	public static String getDomain(HttpServletRequest request) {
		return getDomain(request.getServerName());
	}
	
	/**
	 * @param domain request.getServerName()
	 * @return 根域或ip
	 */
	public static String getDomain(String domain) {
		boolean ip = true;
		int pointCount = 0;
		for (int i = domain.length() - 1; i >=0 ; i--) {
			char ch = domain.charAt(i);
			if (ch == '.') {
				pointCount++;
			} else if (ch < '0' || ch > '9') {
				ip = false;
				break;
			}
		}
		if (ip && pointCount == 3) return null;
		
		int pos2 = domain.lastIndexOf('.');
		if (pos2 == -1 || pos2 == 0) return null;
		
		int pos1 = domain.lastIndexOf('.', pos2 - 1);
		if (pos1 != -1) return domain.substring(pos1);
		return '.' + domain;
	}
	
	
	public static String getCookieValue(HttpServletRequest request, String cookieName) {
		Cookie[] cookies = request.getCookies();
		if (cookies == null) return null;
		
		String sessionId = null;
		for (Cookie cookie : cookies) {
			if (cookieName.equals(cookie.getName())) sessionId = cookie.getValue();
		}
		return sessionId;
	}
	
	
	/** freemarker 从request包装中提取HttpServletRequest */
	public static HttpServletRequest getRequest(Object request) {
		HttpServletRequest req;
		if (request instanceof HttpServletRequest) {
			req = (HttpServletRequest) request;
		} else if (request instanceof HashAdapter) {
			req = ((HttpRequestHashModel) ((HashAdapter) request).getTemplateModel()).getRequest();
		} else if (request instanceof RequestContext) {
			req = UtilObj.getFieldValue(request, "request");
		} else {
			throw new IllegalArgumentException("无法解析HttpServletRequest: " + request);
		}
		return req;
	}
	
	public static ServletWebRequest getServletWebRequest4fm(Object request) {
		if (request instanceof ServletWebRequest) return (ServletWebRequest) request;
		
		if (request instanceof HashAdapter) {
			HttpRequestHashModel model = (HttpRequestHashModel) ((HashAdapter) request).getTemplateModel();
			return new ServletWebRequest(model.getRequest(), model.getResponse());
		} else {
			throw new IllegalArgumentException("无法解析: " + request);
		}
	}

	public static Object getValue(Object request, String name) {
		return getValue(getRequest(request), name);
	}
	
	public static Map<String, Object> getReqInfo(HttpServletRequest request) {
		return getReqInfo(request, true, true);
	}
	public static Map<String, Object> getReqInfo(HttpServletRequest request, boolean remote, boolean headers) {
		Map<String, Object> result = new LinkedHashMap<>();
		if (remote) {
			result.put("remoteAddr", request.getRemoteAddr());
			result.put("remoteHost", request.getRemoteHost());
			result.put("remotePort", request.getRemotePort());
			result.put("remoteUser", request.getRemoteUser());
		}
		if (headers) {
			Map<String, List<String>> map = new LinkedHashMap<>();
			for (Enumeration<String> iter = request.getHeaderNames(); iter.hasMoreElements();) {
				String name = iter.nextElement();
				List<String> values = new ArrayList<>();
				for (Enumeration<String> iter2 = request.getHeaders(name); iter2.hasMoreElements();) {
					values.add(iter2.nextElement());
				}
				map.put(name, values);
			}
			result.put("headers", map);
		}
		
		result.put("authType", request.getAuthType());

		result.put("scheme", request.getScheme());
		result.put("serverName", request.getServerName());
		result.put("serverPort", request.getServerPort());
		result.put("contextPath", request.getContextPath());
		
		result.put("requestURI", request.getRequestURI());
		result.put("requestURL", request.getRequestURL());
		result.put("queryString", request.getQueryString());
		result.put("parameterMap", request.getParameterMap());
		
		return result;
	}
	
	
	/** 签名算法：md5(secret, timestamp, md5(name1, value1, ……, nameDup1, dupV1, dupV2), secret) */
	public static String sign(String secret, Object timestamp, String paramsMd5) {
		String sign = UtilString.md5(secret, timestamp.toString(), paramsMd5, secret);
		logger.trace("timestamp={}, paramsMd5={}, sign={}", timestamp, paramsMd5, sign);
		return sign;
	}

	/** 请求数据的md5码值：md5(name1, value1, ……, nameDup1, dupV1, dupV2) */
	public static String paramsMd5(Object request) {
		HttpServletRequest req = getRequest(request);
		
		//如果经过了Xss那么需要读取原始数据
		Map<String, String[]> tmp = req.getParameterMap();
		
		Map<String, String[]> paramsMap = tmp instanceof TreeMap ? tmp : new TreeMap<>(tmp);
		List<String> params = new ArrayList<>(paramsMap.size() + 4);
		for (Entry<String, String[]> entry : paramsMap.entrySet()) {
			params.add(entry.getKey());
			for (String value : entry.getValue()) {
				params.add(value);
			}
		}
		return UtilString.md5(params);
	}
	
}
